home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / COMPRESS / HUFF_SC.ZIP / HUF.C next >
Encoding:
C/C++ Source or Header  |  1991-04-25  |  28.7 KB  |  816 lines

  1. /*******************************************************************************
  2. *                                                                              *
  3. * HUF.C   by Shaun Case   April 1991                                           *
  4. *                                                                              *
  5. * Written in Borland C++ 2.0 under MS-DOS 3.3                                  *
  6. *                                                                              *
  7. * Uses Huffman encoding to compress a single file.                             *
  8. * This program is in the public domain.                                        *
  9. *                                                                              *
  10. * atman%ecst.csuchico.edu@RELAY.CS.NET                                         *
  11. *                                                                              *
  12. *                                                                              *
  13. *******************************************************************************/
  14.  
  15. #include <stdio.h>
  16. #include <math.h>
  17. #include <dir.h>                        /* for storing filename in output file      */
  18.  
  19. #define FALSE 0                         /* i'm still deciding on a style...         */
  20. #define TRUE !FALSE
  21.  
  22. /*
  23.  * for lots of interesting (?) diagnostics, uncomment the following:
  24. #define VERBOSE
  25.  *
  26.  */
  27.  
  28.  
  29. typedef struct chardata {               /* template for leaves and nodes in tree    */
  30.     short charnum;                      /* which character to be encoded            */
  31.                                         /* don't want it lost in the sort           */
  32.     unsigned long total;                /* total occurances in the file             */
  33.     short seq_length;                   /* length of this char's huffman code (bits)*/
  34.     short bit_sequence;                 /* the huffman code sequence for this char  */
  35.     double frequency;                   /* frequency of occurance, < 1.0            */
  36.     struct chardata *up, *left, *right; /* pointers to rest of tree                 */
  37. };
  38.  
  39. typedef struct decode_table_element {   /* template for decode table element (wow)  */
  40.     unsigned char letter;               /* which character to decode to             */
  41.     char spare;                         /* force 16-bit word alignment              */
  42.     short left;                         /* index of lower left element from tree    */
  43.     short right;                        /* index of lower right element from tree   */
  44. };
  45.  
  46.  
  47. int compare(const void*, const void*);  /* prototype for compare() for qsort()      */
  48.  
  49. struct chardata *huftable[256];         /* array that points to leaves in tree      */
  50. struct chardata *root=NULL;             /* future root of tree                      */
  51. struct decode_table_element *decode_table;  /* pointer to decode table              */
  52. short array_max_index=0;                /* max number of elements in array (to be   */
  53.                                         /* determined in create_decode_table()      */
  54.  
  55. long real_bit_total=0L;
  56. double avg_bits_per_symbol=0;           /* averages num of bits needed to represent */
  57. unsigned long  total;                   /* total number of unencoded bytes          */
  58. long real_bits_total = 0L;
  59. FILE *infile;                           /* file ptr to original file (uncompressed) */
  60. FILE *outfile;                          /* file ptr to output fiel   (compressed)   */
  61. char *infile_name;                      /* ptr to name of input file                */
  62. char *outfile_name;                     /* ptr to name of output file               */
  63.  
  64.  
  65. int main(int argc, char **argv)
  66. {
  67.  
  68. #ifdef VERBOSE
  69.     void show_encode_info(void);                    /* prototype   */
  70.     void show_encoded_file_size(void);              /* prototype   */
  71.     void show_decode_table(void);                   /* prototype   */
  72. #endif
  73.  
  74.     void dumptable(void);                           /* prototype   */
  75.     short create_tree(void);                        /* prototype   */
  76.     void gen_bit_sequences(struct chardata *node);  /* prototype   */
  77.     short create_decode_table(void);                /* prototype   */
  78.     short compress(void);                           /* prototype   */
  79.  
  80.     register short c;                               /* a character */
  81.     
  82.     if (argc != 3) {                                /* check command line arguments */
  83.         puts("'huf file1 file2' encodes file1 into file2.");
  84.         return 1;
  85.     }
  86.     puts("Huf by Shaun Case, 1991, Public Domain");
  87.     infile_name = argv[1];
  88.     outfile_name = argv[2];
  89.  
  90.     puts("Analyzing data.");
  91.  
  92.     for (c=0; c < 256; c++)                         /* initialize decode table      */
  93.     {
  94.         if ((huftable[c] = (struct chardata *)malloc(sizeof (struct chardata)))== NULL)
  95.         {
  96.             printf("Unable to allocate space for %dth huftable node.",c);
  97.             return 1;
  98.         }
  99.         huftable[c]->charnum   = c;                 /* need to know who we are after qsort() gets done with us */
  100.         huftable[c]->total     = 0L;
  101.         huftable[c]->frequency = 0;
  102.         huftable[c]->up        = NULL;
  103.         huftable[c]->left      = NULL;
  104.         huftable[c]->right     = NULL;
  105.     }
  106.  
  107.  
  108.     if ((infile=fopen(infile_name, "rb")) == NULL)  /* open the input file              */
  109.     {
  110.         printf("Unable to open %s.\n", infile_name);
  111.         return 1;
  112.     }
  113.  
  114.     while (!feof(infile))                           /* get character distribution data  */
  115.     {
  116.         c = fgetc(infile);
  117.  
  118.         if (feof(infile))
  119.             continue;
  120.  
  121.         ++total;
  122.         ++huftable[c]->total;                       /* increment total for char c       */
  123.     }
  124.  
  125.     if (total == 0L)                                /* handle empty file                */
  126.     {
  127.         puts("Input file is empty, aborting.");
  128.         return 0;
  129.     }
  130.  
  131.     fclose(infile);
  132.                                                     /* sort according to frequency of occurance */
  133.  
  134.     qsort((void *)huftable, (size_t)256, (size_t)sizeof(struct chardata *),
  135.         compare);
  136.  
  137.     dumptable();                                    /* fill huftable with distribution freqs    */
  138.  
  139.     if (create_tree() != TRUE)                      /* make the huffman tree (bit sequences)    */
  140.         return 1;
  141.  
  142. #ifdef VERBOSE
  143.     printf("\nFreq of root is %f.\n",root->frequency);  /* this should be 1.0 if all went well  */
  144.  
  145.     puts("\nBit sequences:\n\n");
  146. #endif
  147.  
  148.     avg_bits_per_symbol = 0;
  149.     gen_bit_sequences(root);                        /* build bit sequences, stuff seqs &        */
  150.                                                     /* lengths into associated leaves           */
  151.  
  152. #ifdef VERBOSE
  153.     printf("\n\nActual bits per symbol = %f", avg_bits_per_symbol);
  154.     printf("\nActual final data size w/o table should be %f\n",
  155.         avg_bits_per_symbol * (double)total / ((double) 8));
  156.  
  157.     show_encoded_file_size();
  158. #endif
  159.  
  160.     puts("Building decode table...");
  161.     if (create_decode_table() != TRUE)              /* create decode array from tree            */
  162.     {
  163.         puts("Unable to allocate space for decode table, exiting.");
  164.         return 1;
  165.     }
  166.  
  167.     printf("Decode table built, contains %d elements.\n",array_max_index + 1);
  168.  
  169. #ifdef VERBOSE
  170.     show_decode_table();
  171.     show_encode_info();
  172. #endif
  173.  
  174.     if (compress() != 0)                            /* now that we have all necessary info,     */
  175.         return 1;                                   /* perform the compression.                 */
  176.  
  177.     puts("Done.");
  178.     return 0;
  179.  
  180. }
  181.  
  182. /*****************************************************************************
  183.  * this code is going to be a little strange -- we have an array of items    *
  184.  * that are going to be the leaves of the tree, and we have to go upward     *
  185.  * linking them together to make the root.  For algorithm, see my notebook,  *
  186.  * or look up huffman compression in a good algorithms book, or see          *
  187.  * huffman's paper -- "A Method for the Construction of Minimum-Redundancy   *
  188.  * Codes" David A. Huffman, Proceedings of the IRE 40, 1098-- 1101           *
  189.  *                                                                           *
  190.  * after the tree is built, the root of the tree is assigned to the global   *
  191.  * variable root.                                                            *
  192.  *                                                                           *
  193.  * -- Shaun Case                                                             *
  194.  *****************************************************************************/
  195.  
  196. struct chardata *ptr1, *ptr2;          /* 1 = smallest freq, 2 = 2nd smallest */
  197.  
  198. short create_tree()
  199. {
  200.     void find_lowest_freqs(void);      /* prototype */
  201.     short only_one_up_ptr_left(void);  /* prototype */
  202.  
  203.  
  204.     double maxfreq = 0 ;               /* max combined freqency in the tree   */
  205.     struct chardata *new_node = NULL;  /* ptr to new node to be created       */
  206.  
  207.     puts("Creating tree from frequencies...");
  208.  
  209.     while (maxfreq < 0.99999 )         /* while we haven't made the root yet  */
  210.     {
  211.         find_lowest_freqs();           /* find the two lowest combined or     */
  212.                                        /*   unused single frequencies         */
  213.  
  214.         if (                           /* create a new node                   */
  215.             (new_node = (struct chardata *)malloc(sizeof (struct chardata)) )
  216.             == NULL
  217.            )
  218.         {
  219.             puts("Insufficient memory, malloc() failed in create_tree().");
  220.             return FALSE;
  221.         }
  222.                                         /* initialize the new node            */
  223.         new_node->up    = NULL;
  224.         new_node->left  = ptr2;
  225.         new_node->right = ptr1;
  226.         new_node->charnum = -1; /* if you get a lot of -1s when traversing the tree, */
  227.                                 /* you aren't looking at the leaves.                 */
  228.         ptr1->up = new_node;
  229.         ptr2->up = new_node;
  230.  
  231.         new_node->frequency = ptr1->frequency + ptr2->frequency; /* combine 2 old freqs */
  232.  
  233.         maxfreq = new_node->frequency;  /* clever optimization */
  234. #ifdef VERBOSE
  235.         printf("Newly created freq == %f\n", maxfreq);
  236. #endif
  237.     }
  238.  
  239.     root = new_node;                    /* update global variable   */
  240.  
  241.     if (only_one_up_ptr_left())         /* verify tree is correct   */
  242.     {                                   /* algorirthm seems to work */
  243.         puts("Done creating tree.");    /*  fine, this is a saftey  */
  244. #ifdef verbose                          /*  check.                  */
  245.         puts("Win: apparently only one remaining up-pointer.");
  246. #endif
  247.     }
  248.     else
  249.     {
  250.         puts("Lose: apparently more than one remaining up-pointer.");
  251.         return FALSE;
  252.     }
  253.  
  254.     return TRUE;                        /* everything is fine.      */
  255. }
  256.  
  257.  
  258. /************************************************************
  259.  * verify there is only one root after the tree is created  *
  260.  * by making sure only one node has an up pointer that has  *
  261.  * the value NULL.                                          *
  262.  *                                                          *
  263.  * Just a double-check.                                     *
  264.  *                                                          *
  265.  ************************************************************/
  266.  
  267. short only_one_up_ptr_left(void)
  268. {
  269.     short bottom=255;
  270.     register struct chardata *tptr;
  271.     register struct chardata *first_null_up_ptr=NULL;
  272.  
  273.     tptr=huftable[bottom];
  274.  
  275.     while (bottom != -1)
  276.     {
  277.         while (tptr->up != NULL)            /* find root for this leaf       */
  278.             tptr = tptr->up;
  279.  
  280.         if (first_null_up_ptr == NULL)      /* assign uptr to root, 1st time */
  281.             first_null_up_ptr = tptr;
  282.         else
  283.             if (first_null_up_ptr != tptr)  /* uh oh, found another root..   */
  284.                 return FALSE;
  285.  
  286.         --bottom;
  287.     }
  288.  
  289.     return TRUE;
  290. }
  291.  
  292. /****************************************************************
  293.  *                                                              *
  294.  * Find the two smallest combined or unused single frequencies  *
  295.  * in the partially-constructed tree.                           *
  296.  *                                                              *
  297.  ****************************************************************/
  298.  
  299. void find_lowest_freqs(void)
  300. {
  301.     register struct chardata *tptr;
  302.  
  303.     /* the following are local for speed (I think double indirection is slow */
  304.  
  305.     register struct chardata *local_minptr;         /* ptr to smallest unused freq     */
  306.     register struct chardata *local_second_minptr;  /* ptr to 2nd smallest unused freq */
  307.  
  308.     struct chardata dummy;
  309.     short bottom = 255;
  310.  
  311.     dummy.frequency = 2.0;          /* initialize to bigger than 1.000         */
  312.     local_minptr=&dummy;            /* initialize to bigger than 1.000         */
  313.  
  314.     while(bottom != -1)             /* find smallest "unused" frequency of all */
  315.     {
  316.         tptr = huftable[bottom];
  317.  
  318.         if (tptr->total == 0L)      /* skip unused byte values (not all files  */
  319.         {                           /* contain all 256 chars)                  */
  320.             --bottom;
  321.             continue;
  322.         }
  323.  
  324.         while (tptr->up != NULL)    /* find top of tree ending in current leaf */
  325.             tptr = tptr->up;
  326.  
  327.         if (tptr->frequency < local_minptr->frequency)  /* if current < min    */
  328.             local_minptr = tptr;                        /* then min = current  */
  329.  
  330.         --bottom;                   /* keep going... */
  331.     }
  332.  
  333.     /* now find second smallest "unused" frequency   */
  334.  
  335.  
  336.     bottom = 255;                   /* start at the bottom again */
  337.     local_second_minptr=&dummy;     /* initialize to bigger than 1.000         */
  338.  
  339.     while(bottom != -1)
  340.     {
  341.         tptr = huftable[bottom];
  342.  
  343.         if (tptr->total == 0L)      /* skip unused byte values                 */
  344.         {
  345.             --bottom;
  346.             continue;
  347.         }
  348.  
  349.         while (tptr->up != NULL)    /* find top of tree ending in current leaf */
  350.             tptr = tptr->up;
  351.  
  352.         if (
  353.              (tptr->frequency < local_second_minptr->frequency)  /* if current < min2    */
  354.              && (tptr != local_minptr)                           /* and curr <> min1     */
  355.            )
  356.            local_second_minptr = tptr;                           /* then min2 = current  */
  357.  
  358.         --bottom;                   /* keep going... */
  359.     }
  360.  
  361.     ptr1 = local_minptr;
  362.     ptr2 = local_second_minptr;
  363.  
  364. }
  365.  
  366.  
  367. /*******************************************************
  368.  *                                                     *
  369.  * Dump the contents of the huffman table.             *
  370.  * also fills huftable with distribution frequencies   *
  371.  *                                                     *
  372.  *******************************************************/
  373.  
  374.  
  375. void dumptable(void)
  376. {
  377.     register short i;
  378.     int bits_per_char;
  379.     double check_total = 0;
  380.     double percent     = 0;
  381.     double frac;
  382.  
  383. #ifdef VERBOSE
  384.     puts("Totals:\n");
  385. #endif
  386.  
  387. #ifdef VERBOSE
  388.     printf("\n\ntotal chars = %ld.\n", total );
  389. #endif
  390.  
  391.     if (total==0)   /* otherwise get divide by zero error */
  392.         return;
  393.  
  394.     avg_bits_per_symbol=0;
  395.     for (i=0; i< (256); i++)
  396.     {
  397.         huftable[i]->frequency = frac = (((double)huftable[i]->total))/(double)total;
  398.         percent= (double)(100)*frac;
  399.         if (frac >0)
  400.             bits_per_char = (int)ceil( -log10(frac)/log10((double)2));
  401.  
  402. #ifdef VERBOSE
  403.         printf("\n%3d = %6ld = %%%6.3f => %d bits",huftable[i]->charnum,
  404.             huftable[i]->total, percent,
  405.             bits_per_char );
  406. #endif
  407.  
  408.         check_total += percent;
  409.         avg_bits_per_symbol += ((double)bits_per_char) * frac;
  410.  
  411.     }
  412. #ifdef VERBOSE
  413.     printf("\n\nTotal........ %%%6.3f\n", check_total);
  414.     printf("Average bits per symbol = %6.3f\n",avg_bits_per_symbol);
  415.     printf("Total compressed file length w/o decode table = %f\n",
  416.         avg_bits_per_symbol * (double)total / ((double) 8)
  417.     );
  418. #endif
  419.  
  420. }
  421.  
  422. /*********************
  423.  * called by qsort() *
  424.  *********************/
  425.  
  426. int compare(const void *arg1, const void *arg2)
  427. {
  428.  
  429.     long result = (
  430.                     (
  431.                        *(struct chardata **)arg1
  432.  
  433.                     )->total
  434.                   )
  435.  
  436.                   -
  437.  
  438.                   (
  439.                     (
  440.                         *(struct chardata **)arg2
  441.                     )->total
  442.                   );
  443.  
  444.     /* return codes reveresed from normal for descending order */
  445.  
  446.     if (result > 0L) return -1;  /* first > second */
  447.     if (result < 0L) return +1;  /* first < second */
  448.     return 0;                    /* first = second */
  449. }
  450.  
  451.  
  452. /***************************************************************************
  453.  * floating point, backwards trees, dynamic memory allocation,             *
  454.  * and now recursion -- this program has it all!                           *
  455.  *                                                                         *
  456.  * func builds bit sequences at stuffs associated sequence and length into *
  457.  * corresponding leaf node                                                 *
  458.  *                                                                         *
  459.  * Pretty obvious code, if you know recursion.                             *
  460.  *                                                                         *
  461.  ***************************************************************************/
  462.  
  463.  
  464. short seq_len=0;
  465.  
  466.  
  467. void gen_bit_sequences(struct chardata *node)
  468. {
  469.     unsigned short asctobin(char *bit_seq);
  470.  
  471.     static char bit_sequence[16];    /* where to build the huffman bit sequence */
  472.     double frac;
  473.  
  474.     if (node->left != NULL)
  475.     {
  476.         bit_sequence[seq_len++]='1';
  477.         gen_bit_sequences(node->left);
  478.         seq_len--;
  479.     }
  480.  
  481.     if (node->right != NULL)
  482.     {
  483.         bit_sequence[seq_len++]='0';
  484.         gen_bit_sequences(node->right);
  485.         seq_len--;
  486.     }
  487.  
  488.     if (node->right != NULL)    /* we are at an interior node going back up */
  489.         return;
  490.  
  491.     bit_sequence[seq_len] = 0;
  492.  
  493.     node->seq_length = (long)seq_len;
  494.     node->bit_sequence = asctobin(bit_sequence);
  495.  
  496. #ifdef VERBOSE
  497.     printf("%3d == %16s == %4x %3d\n", node->charnum, bit_sequence, node->bit_sequence, seq_len);
  498. #endif
  499.  
  500.     frac = (((double)huftable[node->charnum]->total))/(double)total;
  501.     avg_bits_per_symbol += ((double)seq_len) * frac;
  502.     real_bits_total += (long)seq_len;
  503.  
  504.     
  505. }
  506.  
  507. /*********************************************
  508.  * turn an ASCII representation of a binary  *
  509.  * number into an unsigned short.            *
  510.  *********************************************/
  511.  
  512. unsigned short asctobin(char *bit_seq)
  513. {
  514.     register short i;
  515.     register unsigned short binary_value=0;
  516.  
  517.     for (i = 0; (i < 16) && (bit_seq[i]); i++)
  518.     {
  519.         binary_value <<= 1;
  520.         binary_value |= (bit_seq[i]=='1') ? 1 : 0;
  521.     }
  522.  
  523.     return binary_value;
  524. }
  525.  
  526. /************************************************************
  527.  * build a decode table (an array) from the big fat hairy   *
  528.  * tree structure we created earlier.  the decode table is  *
  529.  * parsed just like the tree, only instead of pointers to   *
  530.  * other nodes, there are left and right array indecies.    *
  531.  * This was done because the destination system for my      *
  532.  * application had no dynamic memory allocation.  Also      *
  533.  * I didn't want to try writing a tree to disk, ick.        *
  534.  ************************************************************/
  535.  
  536. short create_decode_table(void)
  537. {
  538.     void assign_index(struct chardata *node);
  539.     void fill_array(struct chardata *node);
  540.  
  541.     assign_index(root);     /* assign index nums to each node in tree -- use member 'total' for */
  542.                             /* this purpose, since it isn't needed anymore.                     */
  543.  
  544.     /* allocate space for array dynamically, since we don't know */
  545.     /* how big it is going to be.  (will be small if there are   */
  546.     /* only a few different characters that are used repeatedly  */
  547.     /* in the file to be encoded.                                */
  548.  
  549.     decode_table = (struct decode_table_element *) calloc(array_max_index + 1,
  550.         sizeof(struct decode_table_element));
  551.  
  552.     if (decode_table == NULL)
  553.         return FALSE;
  554.  
  555.     fill_array(root);   /* fill up the table */
  556.     return TRUE;
  557. }
  558.  
  559. /***************************************************************************
  560.  * assign all nodes index numbers.  uses preorder traversal to ensure that *
  561.  * the root is assigned 0, which will be the 'root' of the array --        *
  562.  * where the searching starts when decoding.                               *
  563.  * sets value of global, "array_max_index"                                 *
  564.  ***************************************************************************/
  565.  
  566. void assign_index(struct chardata *node)
  567. {
  568.     if (node != NULL)
  569.     {
  570.          node->total = (long)array_max_index++;
  571.          assign_index(node->left);
  572.          assign_index(node->right);
  573.     }
  574. }
  575.  
  576.  
  577. /*************************************************
  578.  * fill up the decode table                      *
  579.  * use preorder traversal (see above for reason) *
  580.  *************************************************/
  581.  
  582. short temp_index = 0;
  583.  
  584. void fill_array(struct chardata *node)
  585. {
  586.     if (node != NULL)
  587.     {
  588.         if (node->left == NULL)     /* we found a leaf */
  589.         {
  590.             decode_table[temp_index].letter = node->charnum;
  591.             decode_table[temp_index].left   = 0;
  592.             decode_table[temp_index].right  = 0;
  593.         }
  594.         else    /* we are at an interior node */
  595.         {
  596.             decode_table[temp_index].letter = '@';  /* if you get a lot of '@' in your decoded */
  597.                                                     /* file you are looking at interior nodes, */
  598.                                                     /* not leaves.                             */
  599.  
  600.             decode_table[temp_index].left   = (short) node->left->total;
  601.             decode_table[temp_index].right  = (short) node->right->total;
  602.         }
  603.  
  604.         temp_index++;
  605.  
  606.         fill_array(node->left);
  607.         fill_array(node->right);
  608.     }
  609. }
  610.  
  611. /***********************
  612.  * perform compression *
  613.  ***********************/
  614.  
  615. short compress(void)
  616. {
  617.     short output_bits(short bit_seq, short seq_len); /* prototype */
  618.     short find_match(int c);                         /* prototype */
  619.  
  620.     register unsigned long i;        /* index variable         */
  621.     register short array_index;      /* index to info for char */
  622.     int c;                           /* a character            */
  623.  
  624.     char orig_name[MAXFILE+MAXEXT],  /* original filename      */
  625.          drive[MAXDRIVE],            /* needed for fnsplit()   */
  626.          dir[MAXDIR],                /* needed for fnsplit()   */
  627.          filename[MAXFILE],          /* 8 chars, orig name     */
  628.          ext[MAXEXT];                /* 3 chars, orig ext      */
  629.  
  630.     if ((infile=fopen(infile_name, "rb")) == NULL)
  631.     {
  632.         printf("Unable to open %s\n", infile_name);
  633.         return 1;
  634.     }
  635.  
  636.     if ((outfile=fopen(outfile_name, "wb")) == NULL)
  637.     {
  638.         printf("Unable to open %s\n", outfile_name);
  639.         return 1;
  640.     }
  641.  
  642.     fnsplit(infile_name, drive, dir, filename, ext);    /* get filename               */
  643.     strcpy(orig_name, filename);
  644.     strcat(orig_name, ext);
  645.     for (i=0; i<13; i++)                                /* write orig filename        */
  646.         fputc(orig_name[i], outfile);                   /* to file one char at a time */
  647.  
  648.                                                         /* write # of array elems     */
  649.     if (
  650.          fwrite((void*)&array_max_index, sizeof(short), 1, outfile)
  651.          < 1
  652.        )
  653.     {
  654.         printf("Unable to write to %s -- out of disk space?", outfile_name);
  655.         fclose(outfile);
  656.         return 1;
  657.     }
  658.                                                         /* write original length      */
  659.     if (
  660.          fwrite((void*)&total, sizeof(unsigned long), 1, outfile)
  661.          < 1
  662.        )
  663.     {
  664.         printf("Unable to write to %s -- out of disk space?", outfile_name);
  665.         fclose(outfile);
  666.         return 1;
  667.     }
  668.                                                         /* write decode table         */
  669.     if (
  670.          fwrite((void*)decode_table, sizeof(struct decode_table_element), array_max_index + 1, outfile)
  671.          < array_max_index
  672.        )
  673.     {
  674.         printf("Unable to write to %s -- out of disk space?", outfile_name);
  675.         fclose(outfile);
  676.         return 1;
  677.     }
  678.  
  679.  
  680.     printf("Encoding %ld bytes.\n",total);
  681.  
  682.     for (i=0; i< total; i++)            /* for all bytes                       */
  683.     {
  684.         c = fgetc(infile);              /* get a new byte                      */
  685.         if (c == EOF)
  686.         {
  687.             printf("\nReached unexpected end of input file at position %ld.\n",i);
  688.             return 1;
  689.         }
  690.         array_index = find_match(c);    /* find it in the decode table         */
  691.  
  692.         if (                            /* write out the bit sequence          */
  693.              output_bits(huftable[array_index]->bit_sequence, (short)huftable[array_index]->seq_length)
  694.              != 0
  695.            )
  696.         {
  697.             printf("Unable to write to %s -- out of disk space?", outfile_name);
  698.             return 1;
  699.         }
  700.     }
  701.  
  702.     output_bits(255,7);                 /* flush last partial char from buffer */
  703.  
  704.     printf("%ld bytes encoded.\n", i);
  705.  
  706.     fclose(outfile);
  707.  
  708.  
  709.     return 0;
  710. }
  711.  
  712. /***************************************
  713.  * return array index that corresponds *
  714.  * to a particular character           *
  715.  ***************************************/
  716.  
  717. short find_match(int c)
  718. {
  719.     register short i=0;
  720.  
  721.     while (c != huftable[i]->charnum)
  722.         ++i;
  723.  
  724.     return i;
  725. }
  726.  
  727. /************************************
  728.  * write out a bit sequence to disk *
  729.  ************************************/
  730.  
  731. short output_bits(short bit_seq, short seq_len)
  732. {
  733.     static unsigned char buffer = 0;
  734.     static unsigned short bits_used   = 0;
  735.     short i;
  736.  
  737.     bit_seq <<= (16 - seq_len);         /* bring 1st real bit to leftmost position */
  738.  
  739.     for (i = 0; i < seq_len; i++)
  740.     {
  741.         buffer <<= 1;                        /* make space for next bit in buffer                      */
  742.         buffer |= ((bit_seq & 0x8000) != 0); /* set rightmost bit of buffer to lefmost bit in sequence */
  743.         bit_seq <<= 1;                       /* throw away used bit from sequence                      */
  744.         bits_used++;                         /* increment bit count                                    */
  745.         if (bits_used == 8)                  /* if we have a whole byte, write it.                     */
  746.         {
  747.             if (fputc((int)buffer, outfile)==EOF)
  748.             {
  749.                 fclose(outfile);
  750.                 return 1;
  751.             }
  752.  
  753.             bits_used = 0;  /* start fresh for new byte                       */
  754.             buffer    = 0;  /* may not be necessary except on final bits/byte */
  755.         }
  756.     }
  757.  
  758.     return 0;
  759. }
  760.  
  761.  
  762. #ifdef VERBOSE
  763.  
  764. void show_encode_info(void)
  765. {
  766.     register short i;
  767.  
  768.     for (i=0; i<256; i++)
  769.         printf("%3d.  charnum =%3d  index == %ld  seq_len =%d, bit_seq = %x\n", i, huftable[i]->charnum,
  770.             huftable[i]->total, huftable[i]->seq_length, huftable[i]->bit_sequence);
  771. }
  772.  
  773. /******
  774.  
  775.  Datafile:  All 16/32 bit quantities in Intel format
  776.  
  777.  
  778.  13 bytes    : original filename (8.3 + "\0")
  779.  16 bits     : number of array elements needed, N (N == 511 means 512 array
  780.                elements -> 0..511)
  781.  32 bits     : size of uncompressed original data in bytes
  782.  N * 6 bytes : Array elements in order 0 .. N
  783.                struct decode_table_element {
  784.                     char letter;      8 bits
  785.                     char spare;       8 bits
  786.                     short left;      16 bits
  787.                     short right;     16 bits
  788.                 }
  789. <?>           : compressed data, effectively a bit stream
  790.  
  791.  ******/
  792.  
  793. void show_encoded_file_size(void)
  794. {
  795.     register unsigned short i;
  796.     double bit_total=0;
  797.  
  798.     for (i = 0; i < 256; i++)
  799.         bit_total += (double)huftable[i]->total
  800.                     *(double)huftable[i]->seq_length;
  801.  
  802.     printf("Best guess at encoded file size is %f bytes.\n", bit_total / (double) 8);
  803.  
  804.  
  805. }
  806.  
  807. void show_decode_table(void)
  808. {
  809.     register unsigned short i;
  810.  
  811.     for (i=0; i<array_max_index+1; i++)
  812.         printf("[%3d]  %3x  L: %3d  R: %3d\n", i, (int)decode_table[i].letter,
  813.             decode_table[i].left, decode_table[i].right);
  814. }
  815. #endif
  816.