huff

list.h

struct list_head {
    struct list_head *prev;
    struct list_head *next;
};

#define LIST_HEAD(head) struct list_head head = {&head, &head}

static inline void INIT_LIST_HEAD(struct list_head *node)
{
    node->prev = node;
    node->next = node;
}

static inline void __list_add(struct list_head *node,
        struct list_head *prev,
        struct list_head *next)
{
    node->prev = prev;
    node->next = next;
    prev->next = node;
    next->prev = node;
}

static inline void list_add(struct list_head *node,
        struct list_head *head)
{
    __list_add(node, head, head->next);
}

static inline void list_add_tail(struct list_head *node,
        struct list_head *head)
{
    __list_add(node, head->prev, head);
}


 

static inline int list_emtpy(struct list_head *head)
{
    return head->next == head;
}

static inline void list_del(struct list_head *node)
{
    node->prev->next = node->next;
    node->next->prev = node->prev;
}

static inline void list_del_init(struct list_head *node)
{
    list_del(node);
    INIT_LIST_HEAD(node);
}

#define offsetof(type, member) \
    ((size_t)(&((type*)0)->member))

#define container_of(ptr, type, member) \
    ({const typeof(((type*)0)->member) *__mptr = ptr; \
     (type*)((char*)__mptr - offsetof(type, member));})

/* @cur: ?..list_head?..?.复?舵.?
 * @head: 澶磋.?圭.?板.
 */
#define list_for_each(cur, head) \
    for (cur = (head)->next; \
        (cur) != (head); \
        cur = (cur)->next)


 

#define list_for_each_safe(cur, tmp, head) \
    for (cur = (head)->next, tmp = (cur)->next; \
        (cur) != (head); \
        cur = tmp, tmp = (tmp)->next)

/* @ptr: ?..list_head?..?€?ㄧ.澶х??.??..?.复?舵.?
 * @head: 澶磋.?圭.?板.
 */
#define list_for_each_entry(ptr, head, member) \
    for ( ptr = container_of((head)->next, typeof(*(ptr)), member); \
        &(ptr)->member != (head); \
        ptr = container_of((ptr)->member.next, typeof(*(ptr)), member) )

#define list_for_each_entry_safe(ptr, tmp, head, member) \
    for ( ptr = container_of((head)->next, typeof(*(ptr)), member); \
        (&(ptr)->member != (head)) && (tmp = container_of((ptr)->member.next, typeof(*(ptr)), member)); \
        ptr = tmp )

#define list_for_each_continue(cur, head) \
    for (cur = (cur)->next; \
        (cur) != (head); \
        cur = (cur)->next)

#define list_for_each_reverse(cur, head) \
    for (cur = (head)->prev; \
        (cur) != (head); \
        cur = (cur)->prev)


 

struct hlist_node {
    struct hlist_node *next;
    struct hlist_node **pprev;
};

struct hlist_head {
    struct hlist_node *first;
};

#define HLIST_HEAD(head) struct hlist_head head = {NULL}

static inline void INIT_HLIST_HEAD(struct hlist_head *head)
{
    head->first = NULL;
}

static inline void INIT_HLIST_NODE(struct hlist_node *node)
{
    node->next = NULL;
    node->pprev = NULL;
}

static inline void hlist_add_head(struct hlist_node *node,
        struct hlist_head *head)
{
    node->next = head->first;
    node->pprev = &head->first;
    head->first = node;
    if (node->next) {
        node->next->pprev = &node->next;
    }
}


 

static inline void hlist_add_before(struct hlist_node *node, struct hlist_node *next)
{
    node->next = next;
    node->pprev = next->pprev;
    *node->pprev = node;
    next->pprev = &node->next;
}

static inline void hlist_add_after(struct hlist_node *prev,
        struct hlist_node *node)
{
    node->next = prev->next;
    node->pprev = &prev->next;
    prev->next = node;
    if (node->next) {
        node->next->pprev = &node->next;
    }
}

static inline void hlist_del(struct hlist_node *node)
{
    *node->pprev = node->next;
    if (node->next) {
        node->next->pprev = node->pprev;
    }
}

static inline void hlist_del_init(struct hlist_node *node)
{
    hlist_del(node);
    INIT_HLIST_NODE(node);
}

static inline int hlist_empty(struct hlist_head *head)
{
    return head->first == NULL;
}


 

#define hlist_for_each(cur, head) \
    for (cur = (head)->first; \
        cur; cur = (cur)->next)

#define hlist_for_each_safe(cur, tmp, head) \
    for (cur = (head)->first; \
        cur && ({tmp = (cur)->next; 1;}); \
        cur = tmp)

#define hlist_for_each_continue(cur, head) \
    for (cur = (cur)->next; \
        cur; cur = (cur)->next)

#define hlist_for_each_from(cur, head) \
    for (; cur; cur = (cur)->next)

#define hlist_for_each_entry(ptr, cur, head, member) \
    for (cur = (head)->first; \
        cur && (ptr = container_of(cur, typeof(*(ptr)), member)); \
        cur = (cur)->next)

#define hlist_for_each_entry_safe(ptr, cur, tmp, head, member) \
    for (cur = (head)->first; \
        cur && (tmp = (cur)->next, 1) && \
        (ptr = container_of(cur, typeof(*(ptr)), member)); \
        cur = tmp)


huff.h

#include "list.h"


#define LEAF_NUM 256
#define MID_NUM ((LEAF_NUM) - 1)

struct hnode_info {
    //?.缉瑙e.涓..涓€涓.?绋.腑杩.?锛..浠ュ.?€?煎.?ㄤ??..锛..浜.?涓..?.缉?.В?..?€瑕..?扮浣跨.涓..?ュ.浠?ㄦ.?..?.缓杩..?..锛.??.>    unsigned short parent;?..?.缓杩..?..锛.??.>
    unsigned short lchild;
    unsigned short rchild;
    //浠ヤ??..?.』?..?.缉?
    size_t weight; //?.€硷?璇ヨ.?瑰.搴..瀛..?ㄦ??.
    size_t code; //??uffman?..?..
    size_t code_len; //琛ㄧずcode涓..澶.?浣..
    struct list_head list; //?ㄤ?瀵?eight?.??...
};

struct pack_tree_node {
    unsigned short parent;
    unsigned short lchild;
    unsigned short rchild;
};

struct pack_head_info {
    size_t src_file_size;
    unsigned short root;
    struct pack_tree_node tab[LEAF_NUM + MID_NUM];
};


 

struct htree_info {
    unsigned short root;
    struct hnode_info *tab;
    FILE *src;
    FILE *pack;
    int (*compress)(struct htree_info *,
        const char *src_file,
        const char *pack_file);
    int (*decompress)(struct htree_info *,
        const char *dst_file,
        const char *pack_file);
};

void htree_init(struct htree_info *);
void htree_destroy(struct htree_info *);


huff.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "huff.h"

#define PTR2NUM(ptr, base) (size_t)(ptr - base)
#define NUM2PTR(n, base) ((base) + (n))

static void fill_weight(struct htree_info *info)
{
    unsigned char buf = 0;
    while (fread(&buf, 1, 1, info->src)) {
        ++info->tab[buf].weight;
/*                printf("%c: %ld\n", buf, NUM2PTR(buf, info->tab)->weight);*/
    }   

    rewind(info->src);
}

//?.ode?..??ead?€?ㄧ.?.??捐〃涓..?.€.?缃.?浣垮??捐
static void list_insert(struct list_head *head,
        struct hnode_info *node)
{
    struct hnode_info *cur = NULL;
    list_for_each_entry(cur, head, list) {
        if (node->weight <= cur->weight) {
            break;
        }   
    }   

    __list_add(&node->list, cur->list.prev, &cur->list);
}


 

static void build_tree(struct htree_info *info)
{
    LIST_HEAD(head);

    size_t i = 0;
    for (i = 0; i < LEAF_NUM; ++i) {
        if (info->tab[i].weight) {
            list_insert(&head, info->tab + i);
        }
    }

    struct hnode_info *pa = NULL;
    struct hnode_info *pb = NULL;

    size_t mid_idx = LEAF_NUM;

    while (head.next->next != &head) {
        pa = container_of(head.next, struct hnode_info, list);
        pb = container_of(head.next->next, struct hnode_info, list);

        info->tab[mid_idx].weight = pa->weight + pb->weight;
        pa->parent = mid_idx;
        pb->parent = mid_idx;
        info->tab[mid_idx].lchild = PTR2NUM(pa, info->tab);
        info->tab[mid_idx].rchild = PTR2NUM(pb, info->tab);

        list_del_init(&pa->list);
        list_del_init(&pb->list);
        list_insert(&head, info->tab + mid_idx);
        ++mid_idx;
    }
    info->root = PTR2NUM(container_of(head.next, struct hnode_info, list), info->tab);
    list_del_init(&info->tab[info->root].list);
}


 

static void fill_code(struct htree_info *info)
{
    unsigned short cur = UNUSED;
    size_t i = 0;
    for (i = 0; i < LEAF_NUM && (cur = i, 1); ++i) {
        if (info->tab[i].weight) {
            while (cur != info->root) {
                if (NUM2PTR(NUM2PTR(cur,info->tab)->parent, info->tab)->rchild == cur) {
                    NUM2PTR(i, info->tab)->code |= 1 << NUM2PTR(i, info->tab)->code_len;
                }
                cur = NUM2PTR(cur, info->tab)->parent;
                ++NUM2PTR(i, info->tab)->code_len;
            }
        }
    }
}


 

static void build_pack(struct htree_info *info)
{
    struct pack_head_info *pack_head = (struct pack_head_info*)malloc(sizeof(struct pack_head_info));

    fseek(info->src, 0, SEEK_END);
    pack_head->src_file_size = ftell(info->src);
    rewind(info->src);

    pack_head->root = info->root;

    size_t i = 0;
    for (i = 0; i < LEAF_NUM + MID_NUM; ++i) {
        //灏..涓..?圭.?.?涓.nsigned short?..?..?板.缂╁.?..
        memcpy(pack_head->tab + i, info->tab + i, sizeof(unsigned short) * 3);
    }

    //?..?.欢澶
    fwrite(pack_head, sizeof(struct pack_head_info), 1, info->pack);

    free(pack_head);

    unsigned char rbuf = 0;
    unsigned char wbuf = 0;
    size_t wbuf_count = 0;
    size_t code_count = 0;
    while (fread(&rbuf, 1, 1, info->src)) {


 

        code_count = NUM2PTR(rbuf, info->tab)->code_len;
        do {
            if (wbuf_count == 8) {
                fwrite(&wbuf, 1, 1, info->pack);
                wbuf = 0;
                wbuf_count = 0;
            }

            wbuf <<= 1;
            wbuf |= NUM2PTR(rbuf, info->tab)->code >> (code_count - 1) & 1;
            ++wbuf_count;

        } while (--code_count);
    }

    wbuf <<= 8 - wbuf_count;
/*        printf("wbuf_count=%ld\n", wbuf_count);*/
    fwrite(&wbuf, 1, 1, info->pack);
}


 

static int compress(struct htree_info *info,
        const char *src_file,
        const char *pack_file)
{
    if (!(info->src = fopen(src_file, "r"))) {
        perror("open src file for compress");
        goto open_srcfile_error;
    }

    if (!(info->pack = fopen(pack_file, "w"))) {
        perror("create pack file for compress");
        goto open_packfile_error;
    }

    info->tab = (struct hnode_info *)malloc(sizeof(struct hnode_info) * (LEAF_NUM + MID_NUM));
    size_t i = 0;
    for (i = 0; i < LEAF_NUM + MID_NUM; ++i) {
        info->tab[i].parent = UNUSED;
        info->tab[i].lchild = UNUSED;
        info->tab[i].rchild = UNUSED;
        info->tab[i].weight = 0;
        info->tab[i].code = 0;
        info->tab[i].code_len = 0;
    }

    fill_weight(info);
    build_tree(info);
    fill_code(info);
    build_pack(info);

    free(info->tab);
    fclose(info->pack);
    fclose(info->src);
    return 0;


 

open_packfile_error:
    fclose(info->src);
open_srcfile_error:
    return -1;
}

static int decompress(struct htree_info *info,
        const char *dst_file,
        const char *pack_file)
{
    //?.?婧..浠?rc_file
    if (!(info->src = fopen(dst_file, "w"))) {
        perror("open src file for compress");
        goto open_srcfile_error;
    }

    if (!(info->pack = fopen(pack_file, "r"))) {
        perror("create pack file for compress");
        goto open_packfile_error;
    }

    struct pack_head_info *pack_head = (struct pack_head_info*)malloc(sizeof(struct pack_head_info));
    fread(pack_head, sizeof(struct pack_head_info), 1, info->pack);

    //寮€濮.В?.缉

    size_t i = 0;
    unsigned char rbuf = 0;
    unsigned short cur = pack_head->root;
    while (fread(&rbuf, 1, 1, info->pack)) {
        for (i = 0; i < 8; ++i) {
            if ((rbuf >> (7 - i)) & 1) {
                cur = NUM2PTR(cur, pack_head->tab)->rchild;
            } else {
                cur = NUM2PTR(cur, pack_head->tab)->lchild;


 

            }
            //?..?颁??跺.?..锛.??..?
            if (cur < LEAF_NUM) {
                fwrite(&cur, 1, 1, info->src);
                if (!(--pack_head->src_file_size)) {
                    break;
                } else {
                    cur = pack_head->root;
                }
            }
        }

    }

    free(pack_head);
    fclose(info->pack);
    fclose(info->src);
    return 0;

open_packfile_error:
    fclose(info->src);
open_srcfile_error:
    return -1;
}


 

void htree_init(struct htree_info *info)
{
    info->root = UNUSED;
    info->tab = NULL;
    info->src = NULL;
    info->pack = NULL;

    info->compress = compress;
    info->decompress = decompress;
}

void htree_destroy(struct htree_info *info)
{
}

 

 

void htree_destroy(struct htree_info *info)
{
}


 

test.c

#include <stdio.h>
#include <string.h>
#include "huff.h"


int main(int argc, char **argv)
{
    const char *banner = "\
?ㄦ?锛.?戒护 ?.. 婧..浠.
?..锛.-c -d
-c锛..缂.
-d锛.В?.
    
    if (argc != 4) {
        goto error_argc;
    }   

    struct htree_info huff;
    htree_init(&huff);

    if (!strcmp(argv[1], "-c")) {
        huff.compress(&huff, argv[2], argv[3]);
    } else if (!strcmp(argv[1], "-d")) {
        huff.decompress(&huff, argv[2], argv[3]);
    } else {
        goto error_argv1;
    }   

    htree_destroy(&huff);
    return 0;

error_argv1:
    htree_destroy(&huff);
error_argc:
    fprintf(stderr, "%s", banner);
    return -1; 
}


 

你可能感兴趣的:(huff)