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; }