とりあえず圧縮部分まで書いてみた。
変換辞書と、データ部分は別ファイルに。
% gcc press.c % ./a.out bar % ls -l bar* -rw-r--r-- 1 sun31048 J03A 24 Nov 16 19:09 bar -rw-r--r-- 1 sun31048 J03A 10 Nov 16 19:10 bar.code -rw-r--r-- 1 sun31048 J03A 4 Nov 16 19:10 bar.data % cat bar aaaaaaaabbbbbbbbaaaaaaaa% cat bar.code 61 1 62 0 % hexdump -b bar.data 0000000 377 000 377 000 0000004 % echo -n a >> bar % ./a.out bar % ls -l bar* -rw-r--r-- 1 sun31048 J03A 25 Nov 16 19:27 bar -rw-r--r-- 1 sun31048 J03A 10 Nov 16 19:27 bar.code -rw-r--r-- 1 sun31048 J03A 5 Nov 16 19:27 bar.data % hexdump -b bar.data 0000000 377 000 377 001 001 % ./a.out press.c % ls -l press.c* -rw-r--r-- 1 sun31048 J03A 3868 Nov 16 19:29 press.c -rw-r--r-- 1 sun31048 J03A 853 Nov 16 19:33 press.c.code -rw-r--r-- 1 sun31048 J03A 2432 Nov 16 19:33 press.c.data
うん、なんだか圧縮できてるっぽいかな? .dataの最後の1バイトだけはフッタみたいなもの。最後から数えて2バイト目のデータは下位何ビットが有効データか、ということを記録している。barがちゃんと圧縮できてるのはわかるけど、press.cがちゃんと圧縮できてるかは、そのデータを伸張して元データを得られるかやってみないとわからんな。
まだ伸張部分書いてないけど。
つーか変換表(.code)の形式をもうちょい考えれば小さくなるな。とりあえず伸張部分書いてからにするけど。
以下プログラムソース。
#include <stdio.h> #include <string.h> #define HCODEMAX 256 typedef struct{ unsigned char c; int count; } item; struct node{ item data; struct node *lbranch, *rbranch; }; struct node** isort(struct node *table[], int length){ int i, j; struct node *tmp; for(i=1;i<length;++i){ for(j=i;j>0 && table[j-1]->data.count>table[j]->data.count;--j){ tmp = table[j-1]; table[j-1] = table[j]; table[j] = tmp; } } return table; } struct node* mknode(item data, struct node *lbranch, struct node *rbranch){ struct node *n; n = (struct node *)malloc(sizeof(struct node)); n->data = data; n->lbranch = lbranch; n->rbranch = rbranch; return n; } struct node* mktree(struct node *table[], int length){ struct node *top_node; item tmp; if(length == 1) return table[0]; tmp.count = table[0]->data.count + table[1]->data.count; table[1] = mknode(tmp, table[0], table[1]); isort(&table[1], length-1); top_node = mktree(&table[1], length-1); return top_node; } int print_htable(FILE *fh, char *htable[256]){ int i; for(i=0;i<256;++i) if(htable[i] != NULL) fprintf(fh, "%02x %s\n", i, htable[i]); return 1; } int mkhtable(char *htable[256], struct node *top_node, char *precode){ char lcode[HCODEMAX], rcode[HCODEMAX]; strcpy(lcode, precode); strcpy(rcode, precode); if(top_node->lbranch != NULL) mkhtable(htable, top_node->lbranch, strcat(lcode, "0")); if(top_node->rbranch != NULL) mkhtable(htable, top_node->rbranch, strcat(rcode, "1")); if(top_node->lbranch == NULL && top_node->rbranch == NULL){ htable[top_node->data.c] = (char *)malloc(sizeof(char)*HCODEMAX); strcpy(htable[top_node->data.c], precode); } return 1; } unsigned int hcode2uint(char *hcode){ unsigned int u, i; u = 0; while(*hcode != '\0'){ u = (u << 1) + *hcode - '0'; ++hcode; } return u; } int putc_archive(int c, char *htable[256], FILE *arch){ static int length = 0; static unsigned int archdata = 0; unsigned char unit; if(c != EOF){ archdata = (archdata << strlen(htable[c])) + hcode2uint(htable[c]); length += strlen(htable[c]); while(length >= 8){ length -= 8; unit = archdata >> length; fputc(unit, arch); archdata = archdata ^ (unit << length); } } else { if(length != 0){ fputc(archdata, arch); } fputc(length, arch); } return 1; } int write_archive(FILE *arch, FILE *plain, char *htable[256]){ int c; while((c = fgetc(plain)) != EOF) putc_archive(c, htable, arch); putc_archive(EOF, htable, arch); return 1; } int compress(char *plainname){ char archname[256], codename[256]; int c, i, j, length; FILE *plain, *arch, *code; struct node *table[256], *top_node; item tmpitem; char *htable[256]; length = 256; strcpy(archname, plainname); strcat(archname, ".data"); strcpy(codename, plainname); strcat(codename, ".code"); if((plain = fopen(plainname, "r")) == NULL){ perror("cannot open plain"); return -1; } if((arch = fopen(archname, "w")) == NULL){ perror("cannot open arch"); return -1; } if((code = fopen(codename, "w")) == NULL){ perror("cannot open tree"); return -1; } for(i=0;i<length;++i){ tmpitem.count = 0; tmpitem.c = i; table[i] = mknode(tmpitem, NULL, NULL); } while((i=fgetc(plain)) != EOF) ++table[i]->data.count; isort(table, length); for(i=0;table[i]->data.count == 0;++i); top_node = mktree(&table[i], length-i); for(i=0;i<256;++i) htable[i] = NULL; mkhtable(htable, top_node, ""); print_htable(code, htable); fseek(plain, 0, SEEK_SET); write_archive(arch, plain, htable); fclose(plain); fclose(code); fclose(arch); return 1; } int main(int argc, char *argv[]){ if(argc>1) if(!compress(argv[argc-1])) puts("cannot compress"); return 0; }
例外処理っていうのかな? そういうのを全然していないような気がする。
プログラミングってやつは、自由度が高くて困ってしまいますね。僕を走らせたいのならレールを敷いてください。なっちゃおうぜ、社会の歯車に。