Exemplo n.º 1
0
/**
 * Open file  and check if it is Huffile. 
 * Return NULL if not Huffile or other mistake, else return Huffile *.
 */
bool isHuffile(char *path) {
    
    // open input
    Huffile* input = hfopen(path, "r");
    if (input == NULL)
    {
        printf("Could not open %s for reading.\n", path);
        return 0;
    }
    
    // read in header
    Huffeader header;
    if (hread(&header, input) == false)
    {
        hfclose(input);
        printf("Could not read header.\n");
        return 0;
    }

    // check for magic number
    if (header.magic != MAGIC)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 0;
    }

    // check checksum
    int checksum = header.checksum;
    for (int i = 0; i < SYMBOLS; i++)
    {
        checksum -= header.frequencies[i];
    }
    if (checksum != 0)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 0;
    }
    
    
    
    // close input
    hfclose(input);
    
    return true;   
}
Exemplo n.º 2
0
int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 2)
    {
        printf("Usage: %s input\n", argv[0]);
        return 1;
    }

    // open input
    Huffile* input = hfopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open %s for reading.\n", argv[1]);
        return 1;
    }

    // read in header
    Huffeader header;
 	   if (hread(&header, input) == false)
    {
        hfclose(input);
        printf("Could not read header.\n");
        return 1;
    }

    // check for magic number
    if (header.magic != MAGIC)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }

    // check checksum
    int checksum = header.checksum;
    for (int i = 0; i < SYMBOLS; i++)
    {
        checksum -= header.frequencies[i];
    }
    if (checksum != 0)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }

    // determine number of rows to use
    const int rows = (int) ceil((LAST - FIRST) / (double) COLS);

    // dump frequencies in a nice table
    printf("\n");
    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < COLS; col++)
        {
            int index = FIRST + row + rows * col;
            if (index > LAST)
            {
                break;
            }
            printf("%c %-6d  ", index, header.frequencies[index]);
        }
        printf("\n");
    }
    printf("\n");

    // dump bits contiguously
    int bit;
    while ((bit = bread(input)) != EOF)
    {
        printf("%d", bit);
    }
    printf("\n\n");

    // close input
    hfclose(input);

    // that's all folks!
    return 0;
}
Exemplo n.º 3
0
//main
int main (int argc, char* argv[])
{
    //keep frequencies in array
    for (int i = 0; i < SYMBOLS; i++)
        frequencies[i] = 0;
    
    //make sure user inputs two arguments
    if (argc != 3)
    {
        printf("You must enter %s input output\n", argv[0]);
        return 1;
    }
    
    //open input 
    FILE *fp = fopen(argv[1],"r" );
    if (fp == NULL)
    {
        printf("Could not open souce file: %s\n", argv[1]);
        return 1;
    }
    
    //open output
    Huffile *outfile = hfopen(argv[2], "w");
    if (outfile == NULL) 
    {
        printf("Could not open destination file: %s\n", argv[2]);
        return 1;
    }   
    
    //create a forest
    Forest *myForest = mkforest();
    if (myForest == NULL)
    {
    	printf("The forest could not be created :(\n");
    	return 1;
    }
    
    //read each character from source file
    for (int c = fgetc(fp); c!= EOF; c = fgetc(fp))
    {
        //printf("%c", c);
        
        //increment frequencies for char
        frequencies[c]++;
        
        //increment checksum
        checksum_counter++;
    }   
    
    //make and plant trees in sorted order
    for (int i = 0; i < SYMBOLS; i++)
    {
        if (frequencies[i] != 0)
        {
            //make the tree
            Tree *tempTree = mktree();
            tempTree->symbol = i;
            tempTree->frequency = frequencies[i];
            tempTree->left = NULL;
            tempTree->right = NULL;
            
            //plant tree in forest
            if (plant(myForest, tempTree) == false)
                printf("Could not plant tree %c\n", i);
        }
    }
    
    //build the huffman tree
    while (myForest->first->tree->frequency < checksum_counter)
    {
        //make the tree
        Tree *tempTree = mktree();
        tempTree->symbol = 0x00;
        tempTree->left = pick(myForest);
        tempTree->right = pick(myForest);
        if (tempTree->right != NULL)
            tempTree->frequency = tempTree->left->frequency + tempTree->right->frequency;
        else
            tempTree->frequency = tempTree->left->frequency;
            
        //plant tree in forest
        if (plant(myForest, tempTree) == false)
            printf("Could not plant parent tree\n");
    }
    
    //create encoding of each character
    for (int i = 0; i < SYMBOLS; i++)
    {
        if (frequencies[i] != 0)
        {
            //create a temporary array to store the encoded value
            char temp[256];
            for (int j = 0; j < 256; j++)
                temp[j] = '9';
            
            encode(myForest->first->tree, i, 0, "", &temp[0]);
            
            //copy temp to encoded
            strncpy(encoded[i], temp, strlen(temp));
            
            //printf("temp: %s\n", temp);
            //printf("encoded: %c, hops: %s ", i, encoded[i]);
        }
    }
    
    //create huffeader header
    Huffeader *header = malloc(sizeof(Huffeader));
    header->magic = MAGIC;
    for (int i = 0; i < SYMBOLS; i++)
        header->frequencies[i] = frequencies[i];
    header->checksum = checksum_counter;
    
    //write header
    hwrite(header, outfile);
   
    //move to beginning of source file
    rewind(fp);
    
    //keep track of how many bits we use
    int bit_count = 0;
    
    //read file per character, lookup frequency, and write to outfile
    for (int c = fgetc(fp); c!= EOF; c = fgetc(fp))
    {
        for (int i = 0; i < strlen(encoded[c]); i++)
        {
            bit_count++;
            
            int bit = 0;
            
            //write each bit
            if (encoded[c][i] == '0')
                bit = 0;
            else if (encoded[c][i] == '1') 
                bit = 1;
                
            bool write_output = bwrite(bit, outfile);
            if (write_output == false)
                printf("Error bwriting: %c\n", encoded[c][i]);
                
            //printf("%c bit_count: %d\n", encoded[c][i], bit_count);
        }
         
        //printf("%s", encoded[c]);
    }
    
    //figure out how many bits in second to last byte are used
    int bits_used = 0;
    if (bit_count <= 8)
        bits_used = bit_count;
    else
        bits_used = (bit_count % 8);
    
    //write trailing bits
    for (int i = 8 - bits_used; i > 1; i--)
    {
        //printf("0\n");
        
        bool write_output = bwrite(0, outfile);
        if (write_output == false)
                printf("Error bwriting: %c\n", '0');
    }  
    
    //cleanup
    outfile->ith = bits_used;
    free(header);
    rmforest(myForest);
    hfclose(outfile);
    fclose(fp);
    
    return 0;
}
Exemplo n.º 4
0
int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 3)
    {
        printf("Usage: %s input output\n", argv[0]);
        return 1;
    }

    // open input
    Huffile* input = hfopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open %s for reading.\n", argv[1]);
        return 1;
    }

    // open outfile
    FILE* outfile = fopen(argv[2], "w");
    
    // read in header
    Huffeader header;
    if (hread(&header, input) == false)
    {
        hfclose(input);
        printf("Could not read header.\n");
        return 1;
    }

    // check for magic number
    if (header.magic != MAGIC)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }

    // check checksum
    int checksum = header.checksum;
    for (int i = 0; i < SYMBOLS; i++)
    {
        checksum -= header.frequencies[i];
    }
    if (checksum != 0)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }
    
    // make forest
    Forest* forest = mkforest();
    
    // search for symbols that are non-zero frequency
    for (int i = 0; i < SYMBOLS; i++)
    {
        // make and plant the trees in the forest
        if (header.frequencies[i] >= 1)
            {
                Tree* newTree = mktree();
                newTree->frequency = header.frequencies[i];
                newTree->symbol = i;
                newTree->left = NULL;
                newTree->right = NULL;
                plant(forest, newTree);
            }
    }
    
    // run loop until there is only one tree left
    bool done = false;
    while (!done)
    {
        // pick smallest tree
        Tree* a = pick(forest);
        
        // pick second smallest tree
        Tree* b = pick(forest);
        
        // if there is only one tree left in the forest, a is the huffman tree
        if (b == NULL)
        {
            done = true;
            root = a;
        }
        
        // if two trees were succesfully picked
        else
        {
            // combine the two trees by calling the combine function
            Tree* combinedTree = combine(a, b);
            
            // plant combined tree back in forest
            plant(forest, combinedTree);
        }

    }

    // write message to file
    int bit;
    Tree* cursor = root;
    while ((bit = bread(input)) != EOF)	
	{	

	    // if bit == 0 -> go left
	    if (bit == 0)
	    {
	        cursor = cursor->left;
	    }

	    // if bit == 1 -> go right
	    else if (bit == 1)
	    {
	       cursor = cursor->right;
	    }

	    // when you find a leaf
	    if ((cursor->right == NULL) && (cursor->left == NULL))
	    {
	        // print the leaf
	        fprintf(outfile, "%c", cursor->symbol);

	        // reset the cursor to root for the next iteration
	        cursor = root;
	    }
	}
    
    // free root
    rmtree(root);
    
    // close forest
    rmforest(forest);
    
    // close input
    hfclose(input);
    
    // close outfile
    fclose(outfile);

    // that's all folks!
    return 0;
}
Exemplo n.º 5
0
/**
 * decompress Huffile and print to file.
 */
bool decompress(char *path1, char *path2) {

    // open input
    Huffile* input = hfopen(path1, "r");
    if (input == NULL)
    {
        printf("Could not open %s for reading.\n", path1);
        return false;
    }

    // read in header
    Huffeader header;
    if (hread(&header, input) == false)
    {
        hfclose(input);
        printf("Could not read header.\n");
        return false;
    }
    
    // open file for writing
    FILE *out = fopen(path2, "w");
    if (out == NULL)
    {
        printf("Could not open %s for writing.\n", path2);
        return false;
    }
    
    // read bits, crawl the tree and write to out
    int bit;
    char ch;
    Tree *p = f->first->tree;
    
    // check single-character file
    if ( count == 1 ) 
    {
        ch = p->symbol;
        if ( fputc(ch, out) == EOF ) 
        {
            printf("can't write\n");
            return false;
        }
        
        return true;
    }
    
    while ((bit = bread(input)) != EOF)
    {   
        
        
        if ( bit == 0 ) 
        {
            p = p->left;
            if ( isLeaf(p) ) 
            {
                ch = p->symbol;
                if ( fputc(ch, out) == EOF ) 
                {
                printf("can't write\n");
                return false;
                }
                p = f->first->tree;
            }    
        }
            
        else if ( bit == 1 )
        {
            p = p->right;
            if ( isLeaf(p) ) 
            {
                ch = p->symbol;
                if ( fputc(ch, out) == EOF )
                {
                printf("can't write\n");
                return false;
                } 
                p = f->first->tree;
            }    
        }
        
        
    }    
    
    return true;
}
Exemplo n.º 6
0
bool createForest(char *path) {
    
    // create empty forest
    f = mkforest();
    
    // open input
    Huffile* input = hfopen(path, "r");
    if (input == NULL)
    {
        printf("Could not open %s for reading.\n", path);
        return 0;
    }
    
    // read in header
    Huffeader header;
    if (hread(&header, input) == false)
    {
        hfclose(input);
        printf("Could not read header.\n");
        return 0;
    }
    
    // read symbols and freq from header, create and plant trees in forest
    
    for (int i = 0; i < SYMBOLS; i++)
    {
        if ( header.frequencies[i] != 0 )
        {   
            Tree *t = mktree();
            t->symbol = i;
            t->frequency = header.frequencies[i];
            plant(f, t);
            count++;
             
        }
             
    }
    
       
    // join trees as siblings
    
    for (int i = 0; i < count - 1; i++) 
    {
        Tree *t = mktree();
        t->left = pick(f);
        t->right = pick(f);
        t->frequency = t->left->frequency + t->right->frequency;
        plant(f, t);
     }   
        
        
        
             
    
    
    
    
    // close input
    hfclose(input);
    
    return true;
    
} 
Exemplo n.º 7
0
int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 3)
    {
        printf("Usage: %s input output\n", argv[0]);
        return 1;
    }

    // open input
    Huffile* input = hfopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open %s for reading.\n", argv[1]);
        return 1;
    }

    // read in header
    Huffeader header;
    if (hread(&header, input) == false)
    {
        hfclose(input);
        printf("Could not read header.\n");
        return 1;
    }

    // check for magic number
    if (header.magic != MAGIC)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }

    // check checksum
    int checksum = header.checksum;
    for (int i = 0; i < SYMBOLS; i++)
    {
        checksum -= header.frequencies[i];
    }
    if (checksum != 0)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }
    int index;
    Forest* f1 = mkforest();
    for(index = 0; index<SYMBOLS;index++)
    {
      if(header.frequencies[index] != 0)
      {
        Tree* t1 = mktree();
        t1->symbol = (char)index;
        t1->frequency = header.frequencies[index];
        plant(f1,t1);
      }
    }
    
    while(true)
    {
        Tree* temp1 = pick(f1);
        Tree* temp2 = pick(f1);
        if(temp2 != NULL)
        {
          Tree* new_tree = mktree();
          new_tree->left = temp1;
          new_tree->right = temp2;
          new_tree->frequency = temp1->frequency + temp2->frequency;
          plant(f1,new_tree);
        }
        else
        {
          plant(f1,temp1);
          break;
        }
    }
    Tree* huffman_tree = pick(f1);
    int bit;
    Tree* temp = huffman_tree;
    FILE *output = fopen(argv[2],"w");
    while ((bit = bread(input)) != EOF)
    {
        if(bit == 1)
        {
            temp = temp->right;
            if(temp->right == NULL && temp->left ==NULL)
            {
              fprintf(output,"%c",temp->symbol);
              temp = huffman_tree;
            }
        }
        else
        {
            temp = temp->left;
            if(temp->right == NULL && temp->left ==NULL)
            {
              fprintf(output,"%c",temp->symbol);
              temp = huffman_tree;
            }
        }
    }

    // close input
    hfclose(input);
    return 0;
}
Exemplo n.º 8
0
/*! <pre>
 *******************************************************************************
 * Function  : hyp_open_file
 * Arguments :
 * Returns   :
 * Purpose   : Attempts to open a hypothesis file that is associated with the opened
 *   PFM specified by the PFM handle. NULL is returned if the file ".hyp"
 *   could not be found.
 *******************************************************************************
 </pre>*/
HypHead*       hyp_open_file( char *list_file_path, NV_INT32 pfmhnd )
{
    HypHead   *hyp;
    char       filename[256];

    /* Form the filename for the .hyp file */
    if( hyp_form_hyp_filename( list_file_path, filename ) < 0 )
    {
        sprintf( hyp_err_str, "Could not locate information from PFM list file '%s'.", list_file_path );
        return NULL;
    }

    /* Create HypHead object */
    hyp = (HypHead*)calloc(1, sizeof(HypHead));
    memset( hyp, 0, sizeof(HypHead) );

    /* Try to open hugeio file */
    hyp->pfmhnd  = pfmhnd;
    hyp->filehnd = hfopen( filename, "r+b" );
    if( hyp->filehnd == -1 )
    {
        hyp->filehnd = hfopen( filename, "rb" );
        hyp->readonly = NVTrue;
    }
    if( hyp->filehnd == -1 )
    {
        sprintf( hyp_err_str, "Could not load cube hypotheses from PFM file '%s'.", list_file_path );
        if (hyp) {
          free( hyp );
          hyp = NULL;
        }
        return NULL;
    }
    hyp->cube_param = (CubeParam *) calloc (1, sizeof(CubeParam));

    /* Read bin header from pfm file */
    read_bin_header( pfmhnd, &hyp->bin_header );

    /* Create the Cube parameters */
/*
    hyp->cube_param = cube_init_param( HYP_DEFAULT_IHO_ORDER, hyp->bin_header.bin_size_xy, hyp->bin_header.bin_size_xy );
    hyp->hypo_resolve_algo    = hyp->cube_param->mthd;
    hyp->node_capture_percent = hyp->cube_param->capture_dist_scale * 100.0f;
*/
    /* Read the header information from the file */
    hyp_read_header( hyp );

    /* Check that hyp version is proper */
    if( hyp->version < 1.0 || hyp->version > HYP_VERSION )
    {
        sprintf( hyp_err_str, "Hypothesis file had unsupported version '%.2f'. This file may have been created with a newer version of the software.", hyp->version );

        if( hyp->cube_param )
          free (hyp->cube_param);
/*
            cube_release_param( hyp->cube_param );
*/

        if (hyp) {
          free( hyp );
          hyp = NULL;
        }
        return NULL;
    }

    /* Check that hyp size is proper */
    if( (hyp->ncols != hyp->bin_header.bin_width) ||
        (hyp->nrows != hyp->bin_header.bin_height) )
    {
        sprintf( hyp_err_str, "Hypothesis file did not match PFM file in size." );

        if (hyp->cube_param ) {
          free (hyp->cube_param);
          hyp->cube_param = NULL;
        }
/*
            cube_release_param( hyp->cube_param );
*/
        if (hyp) {
          free( hyp );
          hyp = NULL;
        }
        return NULL;
    }

    /* Make sure file size matches expected */
    /*
    hfseek( hyp->filehnd, 0, SEEK_END );
    if( hftell( hyp->filehnd ) != hyp->file_size )
    {
        sprintf( hyp_err_str, "Hypothesis file size is not correct. File may have been corrupted." );
        free( hyp );
        return NULL;
    }*/

    /* Return created HypHead object */
    return hyp;
}
Exemplo n.º 9
0
/*! <pre>
 *******************************************************************************
 * Function  : hyp_create_file
 * Arguments :
 * Returns   :
 * Purpose   : Creates a new hypothesis file with extension ".hyp". Associates the
 *   structure with an open handle to a PFM file. The HYP data structure
 *   built will be the same size as the existing PFM file. The attributes tell
 *   the library where to find information from the PFM file. The horizontal
 *   and vertical error attributes are required, but the others can be disabled
 *   by passing -1.
 *******************************************************************************
 </pre>*/
HypHead*       hyp_create_file( char *list_file_path, NV_INT32 pfmhnd,
                NV_INT32 horizErrorAttr, NV_INT32 vertErrorAttr,
                NV_INT32 numHyposAttr, NV_INT32 hypoStrengthAttr,
                NV_INT32 uncertaintyAttr, NV_INT32 customHypoFlag )
{
    HypHead   *hyp;
    char       filename[256], *data;
    NV_INT32   hnd, i, j, percent, old_percent;

    /* Form the filename for the .hyp file */
    if( hyp_form_hyp_filename( list_file_path, filename ) < 0 )
    {
        fprintf(stderr, "Could not locate information from PFM list file '%s'.", list_file_path );
        return NULL;
    }

    /* Try to open hugeio file */
    hnd = hfopen( filename, "w+b" );
    if( hnd == -1 )
    {
        sprintf( hyp_err_str, "Error creating file in '%s'.", filename );
        return NULL;
    }

    /* Create new object and initialize */
    hyp = (HypHead *)calloc(1, sizeof(HypHead));
    memset( hyp, 0, sizeof(HypHead) );
    hyp->cube_param = (CubeParam *) calloc (1, sizeof(CubeParam));
    read_bin_header( pfmhnd, &hyp->bin_header );
    hyp->version            = HYP_VERSION;
    hyp->pfmhnd             = pfmhnd;
    hyp->ncols              = hyp->bin_header.bin_width;
    hyp->nrows              = hyp->bin_header.bin_height;
    hyp->filehnd            = hnd;
    hyp->readonly           = NVFalse;
#ifdef HYP_LITENDIAN
    hyp->endian             = HYP_FTYPE_LITENDIAN;
#else
    hyp->endian             = HYP_FTYPE_BIGENDIAN;
#endif
    hyp->vert_error_attr    = vertErrorAttr;
    hyp->horiz_error_attr   = horizErrorAttr;
    hyp->num_hypos_attr     = numHyposAttr;
    hyp->hypo_strength_attr = hypoStrengthAttr;
    hyp->uncertainty_attr   = uncertaintyAttr;
    hyp->custom_hypo_flag   = customHypoFlag;
    hyp->deleted_ptr        = 0;
    hyp->file_size          = HYP_ASCII_HEADER_SIZE + HYP_BINARY_HEADER_SIZE + ((NV_INT64)hyp->ncols * (NV_INT64)hyp->nrows * HYP_NODE_RECORD_SIZE);

    /* Create the Cube parameters */
/*
    hyp->cube_param      = cube_init_param( HYP_DEFAULT_IHO_ORDER, hyp->bin_header.bin_size_xy, hyp->bin_header.bin_size_xy );
    hyp->hypo_resolve_algo    = hyp->cube_param->mthd;
    hyp->node_capture_percent = hyp->cube_param->capture_dist_scale * 100.0f;
*/
    /* Write the header information to the file */
    hyp_write_header( hyp );

    /* Write empty information for the Nodes */
    hfseek( hyp->filehnd, HYP_ASCII_HEADER_SIZE + HYP_BINARY_HEADER_SIZE, SEEK_SET );
    data        = (char*)malloc( HYP_NODE_RECORD_SIZE );
    memset( data, 0, HYP_NODE_RECORD_SIZE );
    old_percent = 0;
    for( i = 0; i < hyp->nrows; i++ )
    {
        /* Write row data */
        for( j = 0; j < hyp->ncols; j++ )
        {
            hfwrite( (void*)data, HYP_NODE_RECORD_SIZE, 1, hyp->filehnd );
        }

        /* Update status callback */
        percent = (NV_INT32)( ((NV_FLOAT32)i / hyp->nrows) * 100.0 );
        if (percent != old_percent)
        {
            /*  Calls a status callback if register. */
            if (hyp_progress_callback)
                (*hyp_progress_callback) (1, percent);
            old_percent = percent;
        }
    }
    free( data );

    /* Return the created HypHead object */
    return hyp;
}
Exemplo n.º 10
0
int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 3)
    {
        printf("Usage: %s input\n", argv[0]);
        return 1;
    }

    // open input
    Huffile* input = hfopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open %s for reading.\n", argv[1]);
        return 1;
    }

    // open outfile
    FILE* outfile = fopen(argv[2], "w");
    if (outfile == NULL)
    {
        fclose(outfile);
        fprintf(stderr, "Could not create outfile.\n");
        return 2;
    }

    // read in header
    Huffeader header;
    if (hread(&header, input) == false)
    {
        hfclose(input);
        printf("Could not read header.\n");
        return 1;
    }

    // check for magic number
    if (header.magic != MAGIC)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }

    // check checksum
    int checksum = header.checksum;
    for (int i = 0; i < SYMBOLS; i++)
    {
        checksum -= header.frequencies[i];
    }
    if (checksum != 0)
    {
        hfclose(input);
        printf("File was not huffed.\n");
        return 1;
    }

    // make forest
    Forest* forest = mkforest();

    // read in huffeader frequencies
    for (int i = 0; i < SYMBOLS; i++)
    {
         // ignore 0 frequencies
        if (header.frequencies[i] > 0)
        {
            // make new tree for every non-zero frequency occurance
            Tree* new_tree = mktree();
            new_tree->symbol = i;
            new_tree->frequency = header.frequencies[i];
            new_tree->left = NULL;
            new_tree->right = NULL;

            // plant every non-zero frequency tree in forest
            plant(forest, new_tree);
        }
    }

    // run loop until there is only one tree left
    bool done = false;
    while (!done)
    {
        // pick smallest tree from forest
        Tree* a = pick(forest);

        // pick second smallest tree from forest
        Tree* b = pick(forest);

        // if there is no second tree in forest...
        if (b == NULL)
        {
            // break loop
            done = true;
            // set root to tree 'a' (last remaining) tree
            root = a;
        }

        // else there are at least two remaining trees in the forest
        else
        {
            // combine the two trees into a parent tree
            Tree* parent_tree = combine(a, b);

            // plant combined tree in forest
            plant(forest, parent_tree);
        }
    }

    // write message to outfile
    int bit;
    Tree* ptr_location = root;
    while ((bit = bread(input)) != EOF)
    {
        // if bit is 0, go left, else go right
        if (bit == 0)
            ptr_location = ptr_location->left; 

        // if bit is 1, go right
        if (bit == 1)
            ptr_location = ptr_location->right;

        // leaf is found when both branchs are NULL
        if ((ptr_location->left == NULL) && (ptr_location->right == NULL))
        {
            // write leaf's symbol to outfile
            fprintf(outfile, "%c", ptr_location->symbol);

            // reset pointer location to root for next iteration of tree
            ptr_location = root;
        }
    }

    // free root
    rmtree(root);

    // close forest
    rmforest(forest);

    // close input & outfile
    hfclose(input);
    fclose(outfile);

    // that's all folks!
    return 0;
}