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