#include <cstdio> #include <cstdlib> #include <cassert> #include <cstring> #include <algorithm> using std::max; using std::min; using std::fill; using std::swap; using std::copy; #define CODE_SIZE 0x100 typedef struct node_t { unsigned long weight; char code; node_t *lchild; node_t *rchild; }node_t, *pnode_t; pnode_t node[CODE_SIZE]; pnode_t htree = NULL; char file[100]; int hcode[CODE_SIZE][CODE_SIZE]; enum status { s_ok, s_error, s_file_error, s_mem_error }; FILE *pfcode = NULL; void destroy_htree(pnode_t p); bool is_leaf(pnode_t p) { assert(p != NULL); if(p->lchild == NULL) { assert(p->rchild == NULL); return true; } return false; } void assign_node(pnode_t p, unsigned long wei, char code, pnode_t lch, pnode_t rch) { p->weight = wei; p->code = code; p->lchild = lch; p->rchild = rch; } void init_node(pnode_t p, char code) { assign_node(p, 0, code, NULL, NULL); } void destroy_node(pnode_t &p) { destroy_htree(p); delete p; p = NULL; } void destroy_htree(pnode_t p) { if(p != NULL) { destroy_node(p->lchild); destroy_node(p->rchild); } } status make_node_arr() { assert(CODE_SIZE == 0x100); char code; FILE *pf = fopen(file, "rb"); if(pf == NULL) return s_file_error; for(int i=0; i<CODE_SIZE; ++i) { node[i] = new node_t; if(node[i] == NULL) { fclose(pf); pf = NULL; return s_mem_error; } init_node(node[i], (char)i); } int i = 0; static char t[] = {'-', '//', '|', '/'}; printf("/ncoding... "); fread(&code, sizeof(char), 1, pf); while(!feof(pf)) { if(i % 1000000 == 0) printf("/b%c", t[i / 1000000 % sizeof(t)]); ++node[(unsigned char)code]->weight; fread(&code, sizeof(char), 1, pf); ++i; } printf("/b /n"); fclose(pf); pf = NULL; return s_ok; } status combine_node() {//make sure node array is built int m1, m2; pnode_t tnode[CODE_SIZE]; copy(node, node + CODE_SIZE, tnode); while(true) { m1 = m2 = -1; for(int k=0; k<CODE_SIZE; ++k) { if(tnode[k] != NULL) { m1 = k; break; } } assert(m1 != -1); for(int k=m1+1; k<CODE_SIZE; ++k) { if(tnode[k] != NULL) { m2 = k; break; } } if(m2 == -1) break; if(tnode[m1]->weight > tnode[m2]->weight) swap(m1, m2); for(int k=max(m1, m2)+1; k<CODE_SIZE; ++k) { if(tnode[k] != NULL && tnode[k]->weight < tnode[m1]->weight) { m2 = m1; m1 = k; } } pnode_t lch = tnode[m1]; pnode_t rch = tnode[m2]; tnode[m1] = new node_t; if(tnode[m1] == NULL) { for(int i=0; i<CODE_SIZE; ++i) destroy_node(tnode[i]); return s_mem_error; } assign_node(tnode[m1], lch->weight + rch->weight, 0, lch, rch); tnode[m2] = NULL; rch = lch = NULL; } destroy_node(htree); htree = tnode[m1]; tnode[m1] = NULL; return s_ok; } void make_hcode(pnode_t p) {//make sure combine_node() is called static int t[CODE_SIZE]; static int ind = 0; if(is_leaf(p)) { copy(t, t + ind, hcode[(unsigned char)p->code]); hcode[(unsigned char)p->code][ind] = -1; return; } t[ind++] = 0; make_hcode(p->lchild); t[ind - 1] = 1; make_hcode(p->rchild); --ind; } status compress() { if(make_node_arr() != s_ok || combine_node() != s_ok) return s_error; make_hcode(htree); FILE *pif = fopen(file, "rb"); if(pif == NULL) return s_file_error; char cfile[100]; strcpy(cfile, file); strcat(cfile, ".compress"); FILE *pof = fopen(cfile, "wb"); if(pof == NULL) { destroy_node(htree); fclose(pif); pif = NULL; return s_file_error; } for(int i=0; i<CODE_SIZE; ++i) fwrite(&node[i]->weight, sizeof(unsigned long), 1, pof); fwrite(&htree->weight, sizeof(unsigned long), 1, pof); static char bit1[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; static char bit0[] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe}; char out; char ch; int h; int b = 0; int i = 0; printf("/ncompressing... "); static char t[] = {'-', '//', '|', '/'}; fread(&ch, sizeof(char), 1, pif); while(!feof(pif)) { if(i % 1000000 == 0) printf("/b%c", t[i / 1000000 % sizeof(t)]); h = 0; while(hcode[(unsigned char)ch][h] != -1) { if(b == sizeof(bit1)) { b = 0; fwrite(&out, sizeof(char), 1, pof); } if(hcode[(unsigned char)ch][h] == 1) out |= bit1[b];//make 1 if(hcode[(unsigned char)ch][h] == 0) out &= bit0[b];//make 0 ++b; ++h; } ++i; fread(&ch, sizeof(char), 1, pif); } fwrite(&out, sizeof(char), 1, pof); printf("/b /n"); destroy_node(htree); fclose(pif); fclose(pof); pif = pof = NULL; return s_ok; } status decompress() {//make sure combine_node() is called char cfile[100]; strcpy(cfile, file); strcat(cfile, ".compress"); FILE *pif = fopen(cfile, "rb"); if(pif == NULL) return s_file_error; FILE *pof = fopen(file, "wb"); if(pof == NULL) { fclose(pif); pif = NULL; return s_file_error; } unsigned long sz; unsigned long wei; for(int i=0; i<CODE_SIZE; ++i) { fread(&wei, sizeof(unsigned long), 1, pif); node[i] = new node_t; if(node[i] == NULL) { fclose(pif); fclose(pof); pif = pof = NULL; return s_file_error; } assign_node(node[i], wei, (char)i, NULL, NULL); } if(combine_node() != s_ok) { destroy_node(htree); fclose(pif); fclose(pof); pif = pof = NULL; return s_error; } fread(&sz, sizeof(unsigned long), 1, pif); static char bit1[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; char in; int b = 0; pnode_t p = htree; fread(&in, sizeof(char), 1, pif); printf("/ndecompressing... "); static char t[] = {'-', '//', '|', '/'}; for(unsigned long i=0; i<sz; ++i) { if(i % 1000000 == 0) printf("/b%c", t[i / 1000000 % sizeof(i)]); p = htree; while(!is_leaf(p)) { if((in & bit1[b]) == bit1[b]) p = p->rchild; else p = p->lchild; ++b; if(b == sizeof(bit1)) { b = 0; fread(&in, sizeof(char), 1, pif); } } fwrite(&p->code, sizeof(char), 1, pof); } printf("/b /n"); destroy_node(htree); fclose(pif); fclose(pof); pof = pif = NULL; return s_ok; } int main() { char key; while(true) { printf("/nd : decompress/nc : compress/nq : quit/n"); fflush(stdin); key = getchar(); switch(key) { case 'c' : case 'C' : printf("/ninput file name : "); scanf("%s", file); if(compress() != s_ok) printf("/nfailed/n"); else printf("/nsucceed/n"); break; case 'd' : case 'D' : printf("/ninput file name(do not append /".compress/") : "); scanf("%s", file); if(decompress() != s_ok) printf("/nfailed/n"); else printf("/nsucceed/n"); break; case 'q' : case 'Q' : return 0; } } return 0; }