huffman.c 2.36 KB
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

/* A struct for writing to files as
   streams of individual bits */

typedef struct __bit_writer
{
    FILE *file;
    uint8_t byte;
    int mod;
} bit_writer;

bit_writer *bit_writer_init(FILE *file)
{
    bit_writer *bw = malloc(sizeof(bit_writer));
    assert(bw);
    bw->file = file;
    bw->byte = 0;
    bw->mod = 0;
    return bw;
}

void bit_writer_free(bit_writer *bw)
{
    free(bw);
}

void bit_writer_write_bit(bit_writer *bw, bool bit)
{
    bw->byte |= (bit > 0) << (bw->mod++);

    if (bw->mod == 8)
    {
        fwrite(&bw->byte, 1, 1, bw->file);
        bw->byte = 0;
        bw->mod = 0;
    }
}

void bit_writer_flush(bit_writer *bw)
{
    while (bw->mod != 0) bit_writer_write_bit(bw, 0);
}

void write_byte(bit_writer *bw, uint8_t byte)
{

    if (byte <= 143) /* 8 bit encoding */
    {
        uint32_t to_encode = 0x30 + (uint32_t) byte;
        for (int b = 8 - 1; b >= 0; b--)
            bit_writer_write_bit(bw, to_encode & (1 << b));
    } else /* 9 bit encoding */
    {
        uint32_t to_encode = 0x100 + (uint32_t) byte;
        for (int b = 9 - 1; b >= 0; b--)
        {
            // bool to_write = () != 0;
            // printf("Writing %d\n", to_write);
            bit_writer_write_bit(bw, to_encode & (1 << b));
        }
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Usage: %s <input file>\n", argv[0]);
        exit(1);
    }

    char *input_file_name = argv[1];
    char *output_file_name = malloc(sizeof(char) * 
        (strlen(input_file_name) + strlen(".deflate") + 1));
    sprintf(output_file_name, "%s.deflate", input_file_name);

    FILE *input_file = fopen(input_file_name, "r");
    FILE *output_file = fopen(output_file_name, "w");
    free(output_file_name);
    bit_writer *bw = bit_writer_init(output_file);



    bit_writer_write_bit(bw, 1); /* BFINAL */
    
    bit_writer_write_bit(bw, 1); /* BTYPE */
    bit_writer_write_bit(bw, 0);

    // write_byte(bw, 144);

    char c;
    while (fread(&c, 1, 1, input_file))
    {
        // printf("Writing %d\n", (int) c);
        write_byte(bw, c);
    }

    for (int i = 0; i < 7; i++)
        bit_writer_write_bit(bw, 0);

    bit_writer_flush(bw);
    bit_writer_free(bw);
    fclose(output_file);
    fclose(input_file);



    return 0;
}